<?php
/**
* 描述：文件上传类，将"上传文件"所需的功能包装在一起，组织起来提供完善的PHP上传功能。
* @final   yes
* @package tryLibrary.base
* @version 1.0
* @copyright (c) 2014/05, jopseh
*/
final class Uploader{
    /**
    * @const int PHP系统中除上传成功的其它错误总代称。
    */
    const UPLOAD_ERR=-999;

    /**
    * @const int 设置上传属性的值不正确。
    */
    const UPLOAD_ERR_CUSTOM_ATTRIBUTE=-8;

    /**
    * @const int 文件移动失败。
    */
    const UPLOAD_ERR_CUSTOM_MOVE=-7;

    /**
    * @const int 非法文件名。
    */
    const UPLOAD_ERR_CUSTOM_FILENAME=-6;

    /**
    * @const int 自动生成文件名函数错误。
    */
    const UPLOAD_ERR_CUSTOM_AUTONAMEFUNCTION=-5;

    /**
    * @const int 上传路径不存在。
    */
    const UPLOAD_ERR_CUSTOM_PATH=-4;

    /**
    * @const int 文件类型不符合设置要求。
    */
    const UPLOAD_ERR_CUSTOM_EXT=-3;

    /**
    * @const int 文件体积不符合设置要求。
    */
    const UPLOAD_ERR_CUSTOM_SIZE=-2;

    /**
    * @const int 文件域不存在。
    */
    const UPLOAD_ERR_CUSTOM_NOFIELD=-1;

    /**
    * @const int=0 文件上传成功。
    */
    const UPLOAD_ERR_OK=UPLOAD_ERR_OK;

    /**
    * @const int=1 上传文件大小超出了php.ini中upload_max_filesize的值。
    */
    const UPLOAD_ERR_INI_SIZE=UPLOAD_ERR_INI_SIZE;

    /**
    * @const int=2 上传文件大小超出了表单中MAX_FILE_SIZE的值。
    */
    const UPLOAD_ERR_FORM_SIZE=UPLOAD_ERR_FORM_SIZE;

    /**
    * @const int=3 文件只上传了一部分，没有被全部上传。
    */
    const UPLOAD_ERR_PARTIAL=UPLOAD_ERR_PARTIAL;

    /**
    * @const int=4 文件域中没有文件。
    */
    const UPLOAD_ERR_NO_FILE=UPLOAD_ERR_NO_FILE;

    /**
    * @const int=6 找不到临时目录。
    */
    const UPLOAD_ERR_NO_TMP_DIR=UPLOAD_ERR_NO_TMP_DIR;

    /**
    * @const int=7 写入失败，可能没有权限。
    */
    const UPLOAD_ERR_CANT_WRITE=UPLOAD_ERR_CANT_WRITE;

    /**
    * @const int=8 文件上传过程中被停止。
    */
    const UPLOAD_ERR_EXTENSION=UPLOAD_ERR_EXTENSION;

    /**
    * @const string 预定义图像文件类型。
    */
    const UPLOAD_EXT_IMAGE='gif,jpg,png,bmp';

    /**
    * @const string 预定义文档文件类型。
    */
    const UPLOAD_EXT_FILE='pdf,txt,doc,docx,xls,xlsx';

    /**
    * @const string 上传类型之单文件上传。
    */
    const UPLOADTYPE_SINGLE='single';

    /**
    * @const string 上传类型之单元多文件上传之全部合乎规格。
    */
    const UPLOADTYPE_MULTI_ALL='all';

    /**
    * @const string 上传类型之单元多文件上传之部分合乎规格。
    */
    const UPLOADTYPE_MULTI_PART='part';

    /**
    * @const string 上传类型之多元上传之全部合乎规格。
    */
    const UPLOADTYPE_MULTIPLEX_ALL='multiplex_all';

    /**
    * @const string 上传类型之多元上传之部分合乎规格。
    */
    const UPLOADTYPE_MULTIPLEX_PART='multiplex_part';

    /**
    * 是否只检查一次上传设置。
    * @var    bool
    * @access private
    */
    private $isCheckAttributeOnce=FALSE;

    /**
    * 检查上传设置不合要求是否停止。
    * @var    bool
    * @access private
    */
    private $isCheckAttributeErrorStop=FALSE;

    /**
    * 是否只检查文件域对象一次。
    * @var    bool
    * @access private
    */
    private $isCheckFieldOnce=FALSE;

    /**
    * 检查文件域对象发生错误是否停止。
    * @var    bool
    * @access private
    */
    private $isCheckFieldErrorStop=FALSE;

    /**
    * 文件上传对象组。
    * @var    array
    * @access private
    */
    private $Field=array();

    /**
    * 存储上传过程中错误代码。
    * @var     int|array
    * @access  private
    * @default array();
    */
    private $ErrorCode=NULL;

    /**
    * 存储上传过程中错误信息。
    * @var     string|array
    * @access  private
    * @default array();
    */
    private $ErrorMessage=NULL;

    /**
    * 存储上传后的文件名。
    * @var    string
    * @access private
    */
    private $Filename=array();

    /**
    * 上传文件的数量。
    * @var     int
    * @default 0
    * @access  private
    */
    private $UploadCount=0;

    /**
    * 文件域的数量。
    * @var     int
    * @default 0
    * @access  private
    */
    private $FieldCount=0;

    /**
    * 指示是不是第一次使用addfile方法。
    * @var     bool
    * @default TRUE
    * @access  private
    */
    private $isFirstAddFile=TRUE;

    /**
    * 上传文件类型，值是single或multi。
    * @var      string
    * @default single
    * @access  public
    */
    public $Type='single';

    /**
    * 指定上传文件要符合的大小。
    * @var      int
    * @default 307200
    * @access  public
    */
    public $Size=307200;

    /**
    * 指定上传文件要我们要符合的扩展名。
    * @var     array
    * @access  public
    */
    public $Extension=NULL;

    /**
    * 指定上传文件要上传的路径。
    * @var      string
    * @access  public
    */
    public $Path=NULL;

    /**
    * 是否自动命名。
    * @var     bool
    * @default TRUE
    * @access  public
    */
    public $AutoNaming=TRUE;

    /**
    * 自动命名函数。
    * @var     function
    * @access  public
    */
    public $AutoNamingFunction;

    /**
    * 是否自动路径。
    * @var      bool
    * @default TRUE
    * @access  public
    */
    public $AutoPath=TRUE;

    /**
    * 描述：获取相关属性。
    * @param  string $name required 要获取的属性名。
    * @return mix
    */
    public function __Get($name){
        switch ($name){
            case 'ErrorCode':
                return $this->ErrorCode;
            break;
            case 'ErrorMessage':
                return $this->ErrorMessage;
            break;
            case 'Filename':
                return $this->Filename;
            break;
            case 'UploadCount':
                return $this->UploadCount;
            break;
            case 'FieldCount':
                return $this->FieldCount;
            break;
            case 'Field':
                return $this->Field;
            break;
        }
    }

    /**
    * 描述：构造函数。
    * @param  FIELS $parameters options $_FIELS标量名称。
    * @return void
    */
    public function __Construct(){
        $arguments=func_get_args();
        for($i=0;$i<count($arguments);$i++){
            $this->Field[$arguments[$i]]=array(
                'fieldName'=>$arguments[$i]
            );
            $this->FieldCount=$this->FieldCount+1;
        }
    }

    /**
    * 描述：增加文件上传对象，针对多文件上传。
    * @param  string $fileControlName required 文件域名称。
    * @param  string $filesize        required 文件体积限制。
    * @param  string $expendName      required 文件类型限制。
    * @param  string $uploadPath      required 上传路径。
    * @return void
    * @access public
    */
    public function AddFile($fieldName,$filesize=NULL,$expendName=NULL,$uploadPath=NULL,$autoPath=NULL,$autoNaming=NULL,$autoNamingFunction=NULL){
        if(($this->Type===Uploader::UPLOADTYPE_MULTIPLEX_ALL||$this->Type===Uploader::UPLOADTYPE_MULTIPLEX_PART)
            &&$this->isFirstAddFile===TRUE){
            $this->Field=array();
            $this->FieldCount=0;
        }
        //--
        $this->Field[$fieldName]=array(
            'fieldName'=>$fieldName,
            'size'=>$filesize,
            'ext'=>$expendName,
            'path'=>$uploadPath,
            'autoPath'=>$autoPath,
            'autoNaming'=>$autoNaming,
            'autoNamingFunction'=>$autoNamingFunction
        );
        $this->FieldCount=$this->FieldCount+1;
        $this->isFirstAddFile=FALSE;
    }

    /**
    * 描述：根据文件调用方式执行上传文件过程。
    * @return void
    * @access public
    */
    public function Execute(){
        //#初始化上传基本要求。
        $this->InitializeBase();
        //#初始化errorCode和errorMessage。
        $this->InitializeError();
        //#检查上传设置，出错将终止整个上传流程。
        $this->CheckAttribute();
        exit();/**调试到这里了*/
        if($this->IsUploadStop()){
            return;
        }
        //#检测文件域对象，出错也将终止整个上传流程。
        $this->CheckFields();
        if($this->IsUploadStop()){
            return;
        }
        //#开始上传文件。
        foreach($this->Field as $field){
            $this->Upload($field);
        }
    }

    /**
    * 描述：检查上传类型代模。
    * @return void
    * @access private
    */
    private function InitializeBase() {
        //#检查上传代模(类型)是否属指定值。
        $uploadType=array(
            Uploader::UPLOADTYPE_SINGLE,
            Uploader::UPLOADTYPE_MULTI_ALL,Uploader::UPLOADTYPE_MULTI_PART,
            Uploader::UPLOADTYPE_MULTIPLEX_ALL,Uploader::UPLOADTYPE_MULTIPLEX_PART
        );
        //#如果代模不正确将报错终止整个PHP进程。
        if(!in_array($this->Type,$uploadType)){
            $errorMessage=$this->MakeErrorMessage(
                'Type','UPLOAD_ERR_CUSTOM_ATTRIBUTE',self::UPLOAD_ERR_CUSTOM_ATTRIBUTE,
                'The value of Type is error,single、multi、part、multiplex_all、multiplex_part.'
            );
            header('HTTP/1.1 500 Internal Server Error!');
            trigger_error($errorMessage,E_USER_ERROR);
        }
        //#检查上传设置只检查一次标识。
        if($this->Type===Uploader::UPLOADTYPE_SINGLE
         ||$this->Type===Uploader::UPLOADTYPE_MULTI_ALL
         ||$this->Type===Uploader::UPLOADTYPE_MULTI_PART){
            $this->isCheckAttributeOnce=TRUE;
        }
        //#检查上传设置发生错误的指示停止标识。
        if($this->Type===Uploader::UPLOADTYPE_SINGLE
         ||$this->Type===Uploader::UPLOADTYPE_MULTI_ALL
         ||$this->Type===Uploader::UPLOADTYPE_MULTI_PART
         ||$this->Type===Uploader::UPLOADTYPE_MULTIPLEX_ALL){
            $this->isCheckAttributeErrorStop=TRUE;
        }
        //#是否只检查文域对象组一次。
        if($this->Type===Uploader::UPLOADTYPE_SINGLE){
            $this->isCheckFieldOnce=TRUE;
        }
        //#检查文件域对象检测出错误是否停止。
        if($this->Type===Uploader::UPLOADTYPE_SINGLE
         ||$this->Type===Uploader::UPLOADTYPE_MULTI_ALL
         ||$this->Type===Uploader::UPLOADTYPE_MULTIPLEX_ALL){
            $this->isCheckFieldErrorStop=TRUE;
        }
    }

    /**
    * 描述：根据不同的上传类型设置errorCode和errorMessage的形态。
    * @return void
    * @access private
    */
    private function InitializeError() {
        if($this->Type===Uploader::UPLOADTYPE_SINGLE){
            $this->ErrorCode=NULL;
            $this->ErrorMessage=NULL;
        }
        elseif($this->Type===Uploader::UPLOADTYPE_MULTI_PART
               ||$this->Type===Uploader::UPLOADTYPE_MULTI_ALL){
            $this->ErrorCode=array('default'=>NULL,'field'=>array());
            $this->ErrorMessage=array('default'=>NULL,'field'=>array());
        }
        elseif($this->Type===Uploader::UPLOADTYPE_MULTIPLEX_ALL
               ||$this->Type===Uploader::UPLOADTYPE_MULTIPLEX_PART){
            $this->ErrorCode=array();
            $this->ErrorMessage=array();
        }
    }

    /**
    * 描述：Execute辅助方法之检查上传设置。
    * @return void
    * @access private
    */
    private function CheckAttribute(){
        $checkData=array(
            'size'=>$this->Size,
            'ext'=>$this->Extension,
            'path'=>$this->Path,
            'autoPath'=>$this->AutoPath,
            'autoNamingFunction'=>$this->AutoNamingFunction
        );
        //--
        foreach($this->Field as $fieldName=>&$field){
            //#如果是多元上传则补其属性。
            if(!$this->isCheckAttributeOnce){
                $field['object']=$_FILES[$fieldName];
                if(!array_key_exists('size',$field)
                  ||is_null($field['size'])
                  ||empty($field['size'])){
                    $field['size']=$this->Size;
                }
                //--
                if(!array_key_exists('ext',$field)
                  ||is_null($field['ext'])
                  ||empty($field['ext'])){
                    $field['ext']=$this->Extension;
                }
                //--
                if(!array_key_exists('path',$field)
                  ||is_null($field['path'])
                  ||empty($field['path'])){
                    $field['path']=$this->Path;
                }
                //--
                if(!array_key_exists('autoPath',$field)
                  ||is_null($field['autoPath'])
                  ||empty($field['autoPath'])){
                    $field['autoPath']=$this->AutoPath;
                }
                //--
                if(!array_key_exists('autoNaming',$field)
                  ||is_null($field['autoNaming'])
                  ||empty($field['autoNaming'])){
                    $field['autoNaming']=$this->AutoNaming;
                }
                //--
                if(!array_key_exists('autoNamingFunction',$field)
                  ||is_null($field['autoNamingFunction'])
                  ||empty($field['autoNamingFunction'])){
                    $field['autoNamingFunction']=$this->AutoNamingFunction;
                }
                //@重造检查数据。
                $checkData=array(
                    'size'=>$field['size'],
                    'ext'=>$field['ext'],
                    'path'=>$field['path'],
                    'autoPath'=>$field['autoPath'],
                    'autoNamingFunction'=>$field['autoNamingFunction']
                );
            }
            //#检查上传指定的文件体积。
            if(!is_numeric($checkData['size'])){
                $this->SetError(self::UPLOAD_ERR_CUSTOM_ATTRIBUTE,$this->MakeErrorMessage(
                    'Attribute::Size','UPLOAD_ERR_CUSTOM_ATTRIBUTE',self::UPLOAD_ERR_CUSTOM_ATTRIBUTE,
                    'Size value is not numeric.'
                ),'default',$fieldName);
                //--
                if($this->isCheckAttributeErrorStop){
                    break;
                }
                else{
                    continue;
                }
            }
            //#检查上传文件扩展名。
            if(!is_array($checkData['ext'])
              ||array_keys($checkData['ext'])!==range(0,count($checkData['ext'])-1)){ //如果数字数组。
                $this->SetError(self::UPLOAD_ERR_CUSTOM_ATTRIBUTE,$this->MakeErrorMessage(
                    'Attribute::Extension','UPLOAD_ERR_CUSTOM_ATTRIBUTE',self::UPLOAD_ERR_CUSTOM_ATTRIBUTE,
                    "Extension value type must be digital array,for example:array('gif','png')."
                ),'default',$fieldName);
                //--
                if($this->isCheckAttributeErrorStop){
                    break;
                }
                else{
                    continue;
                }
            }
            exit('调试到这里了');
            //#检查上传文件路径。
            if(!isset($checkData['path'])&&empty($checkData['path'])){
                $this->SetError(self::UPLOAD_ERR_CUSTOM_ATTRIBUTE,$this->MakeErrorMessage(
                    'Attribute::Path','UPLOAD_ERR_CUSTOM_ATTRIBUTE',
                    self::UPLOAD_ERR_CUSTOM_ATTRIBUTE,'Upload path value is NULL or empty.'
                ),'default',$fieldName);
                //--
                if($this->isCheckAttributeErrorStop){
                    break;
                }
                else{
                    continue;
                }
            }
            //#检查命名函数。
            if(isset($checkData['autoNamingFunction'])){
                if('object'!==gettype($checkData['AutoNamingFunction'])){
                    $this->SetError(self::UPLOAD_ERR_CUSTOM_ATTRIBUTE,$this->MakeErrorMessage(
                        'Attribute::AutoNamingFunction','UPLOAD_ERR_CUSTOM_ATTRIBUTE',
                        self::UPLOAD_ERR_CUSTOM_ATTRIBUTE,'AutoNamingFunction value is not Funtion.'
                    ),'default',$fieldName);
                    //--
                    if($this->isCheckAttributeErrorStop){
                        break;
                    }
                    else{
                        continue;
                    }
                }
            }
            //#检查上传路径，没有则创建。
            if(!is_dir($checkData['path'])){
                if($checkData['autoPath']){
                    $this->CreatePath($checkData['path']);
                }
                else{
                    $this->SetError(self::UPLOAD_ERR_CUSTOM_ATTRIBUTE,$this->MakeErrorMessage(
                        'Attribute::AutoPath','UPLOAD_ERR_CUSTOM_ATTRIBUTE',self::UPLOAD_ERR_CUSTOM_ATTRIBUTE,
                        sprintf('Upload path not exist,Meanwhile autoPath attribute value is FALSE,the path is %s.',$checkData['path'])
                    ),'default',$fieldName);
                    //--
                    if($this->isCheckAttributeErrorStop){
                        break;
                    }
                    else{
                        continue;
                    }
                }
            }
            //#如果是单文件上传则终止
            if($this->isCheckAttributeOnce){
                break;
            }
        }
    }

    /**
    * 描述：检测文件域并根据具体情况处理文件域。
    * @return bool
    * @access private
    */
    private function CheckFields(){
        foreach($this->Field as &$field){
            $fieldName=$field['fieldName'];
            //--
            if(isset($_FILES[$fieldName])){
                if($field['object']['error']===self::UPLOAD_ERR_OK){   //检测$FIELD标量的PHP引擎错误。
                    $temp=$this->GetExtName($field['object']['name']); //检测文件域扩展名正确性。
                    if(!in_array($temp,$field['ext'])){
                        $errorMessage=$this->MakeErrorMessage(
                            'Upload::CheckFields','UPLOAD_ERR_CUSTOM_EXT',self::UPLOAD_ERR_CUSTOM_EXT,
                            sprintf('File extension is error,option extension is %s,upload file extension is %s.',implode(' or ',$field['ext']),$temp)
                        );
                        $this->SetError(self::UPLOAD_ERR_CUSTOM_EXT,$errorMessage,'field',$fieldName);
                        if($this->isCheckFieldErrorStop){
                            break;
                        }
                        else{
                            continue;
                        }
                    }
                    else{
                        //检测文件域体积正确性。
                        if($field['size']<$field['object']['size']){
                            $errorMessage=$this->MakeErrorMessage(
                                'Upload::CheckFields','UPLOAD_ERR_CUSTOM_SIZE',self::UPLOAD_ERR_CUSTOM_SIZE,
                                sprintf('Filesize greater than option size. option size is %s.',$field['uploadSize'])
                            );
                            $this->SetError(self::UPLOAD_ERR_CUSTOM_SIZE,$errorMessage,'field',$fieldName);
                            if($this->isCheckFieldErrorStop){
                                break;
                            }
                            else{
                                continue;
                            }
                        }
                        else{
                            //没错也标出是UPLOAD_ERR_OK。
                            $this->SetError(self::UPLOAD_ERR_OK,'','field',$fieldName);
                        }
                    }
                }
                else{
                    $PHPUploadErrorName=array(
                        UPLOAD_ERR_OK=>'UPLOAD_ERR_OK',                 //文件上传成功。@
                        UPLOAD_ERR_INI_SIZE=>'UPLOAD_ERR_INI_SIZE',     //上传文件大小超出了php.ini中upload_max_filesize的值。
                        UPLOAD_ERR_FORM_SIZE=>'UPLOAD_ERR_FORM_SIZE',   //上传文件大小超出了表单中MAX_FILE_SIZE的值。
                        UPLOAD_ERR_PARTIAL=>'UPLOAD_ERR_PARTIAL',       //文件只上传了一部分，没有被全部上传。
                        UPLOAD_ERR_NO_FILE=>'UPLOAD_ERR_NO_FILE',       //文件域中没有文件。
                        UPLOAD_ERR_NO_TMP_DIR=>'UPLOAD_ERR_NO_TMP_DIR', //找不到临时目录。
                        UPLOAD_ERR_CANT_WRITE=>'UPLOAD_ERR_CANT_WRITE', //写入失败，可能没有权限。
                        UPLOAD_ERR_EXTENSION=>'UPLOAD_ERR_EXTENSION'    //文件上传过程中被停止。
                    );
                    //--
                    $temp=$PHPUploadErrorName[$field['object']['error']];
                    $errorMessage=$this->MakeErrorMessage('Upload::CheckFields',$temp,$field['object']['error'],
                        sprintf('Field error is PHP engine error,name is %s.',$temp)
                    );
                    $this->SetError($field['object']['error'],$errorMessage,'field',$fieldName);
                    //--
                    if($this->isCheckFieldErrorStop){
                        break;
                    }
                    else{
                        continue;
                    }
                }
            }
            else{
                //@检测出无文件域变量。
                $errorMessage=$this->MakeErrorMessage(
                    'Upload::CheckFields','UPLOAD_ERR_CUSTOM_NOFIELD',self::UPLOAD_ERR_CUSTOM_NOFIELD,
                    sprintf('File field not exist,the name is %s.',$fieldName)
                );
                $this->SetError(self::UPLOAD_ERR_CUSTOM_NOFIELD,$errorMessage,'field',$fieldName);
                if($this->isCheckFieldErrorStop){
                    break;
                }
                else{
                    continue;
                }
            }
            //--
            if($this->isCheckFieldOnce){
                break;
            }
        }
    }

    /**
    * 描述：上传文件。
    * @param  field $fielObject required $_FIELS标量。
    * @return void
    * @access private
    */
    private function Upload($field){
        //#如果上传模式是part，需要筛选上传。
        if($this->Type===Uploader::UPLOADTYPE_MULTI_PART){
            if($this->ErrorCode['field'][$field['fieldName']]!==Uploader::UPLOAD_ERR_OK){
                return;
            }
        }
        elseif($this->Type===Uploader::UPLOADTYPE_MULTIPLEX_PART){
            if($this->ErrorCode[$field['fieldName']]!==Uploader::UPLOAD_ERR_OK){
                return;
            }
        }
        //#定义基本标量。
        $filename=$field['object']['name'];
        $extName=$this->GetExtName($filename);
        if($this->isCheckAttributeOnce){
            $autoNaming=$this->AutoNaming;
            $autoNamingFunction=$this->AutoNamingFunction;
            $path=$this->Path;
        }
        else{
            $autoNaming=$field['autoNaming'];
            $autoNamingFunction=$field['autoNamingFunction'];
            $path=$field['path'];
        }
        //#处理自动命名。
        if($autoNaming){
            if($autoNamingFunction){
                $filename=$autoNamingFunction($filename);     //用户自定义函数生成。
            }
            else{
                $filename=date('Ymd').time().rand(1000,2000); //默认生成。
            }
            //@检测文件名是为空，拼凑完整文件名。
            if(empty($filename)||is_null($filename)){
                $this->SetError(self::UPLOAD_ERR_CUSTOM_FILENAME,$this->MakeErrorMessage(
                    'Upload','UPLOAD_ERR_CUSTOM_FILENAME',self::UPLOAD_ERR_CUSTOM_FILENAME,
                    sprintf('Create the file name is nonlicet,filename is empty.',$filename)
                ),'field',$field['fieldName']);
                return;
            }
            $filename=$filename.'.'.$extName;
            //@检测文名长度。
            if(strlen($filename)>127){
                $this->SetError(self::UPLOAD_ERR_CUSTOM_FILENAME,$this->MakeErrorMessage(
                    'Upload','UPLOAD_ERR_CUSTOM_FILENAME',self::UPLOAD_ERR_CUSTOM_FILENAME,
                    sprintf('Create the file name is nonlicet,filename is too long,length is 127 bytes.',$filename)
                ),'field',$field['fieldName']);
                return;
            }
        }
        //#移动文件
        if(@move_uploaded_file($field['object']['tmp_name'],str_replace('//','/',$path).'/'.$filename)){
            if($this->Type===Uploader::UPLOADTYPE_SINGLE){
                $this->Filename=$filename;
            }
            else{
                $this->Filename[$field['fieldName']]=$filename;
            }
            $this->UploadCount+=1;
        }
        else{
            $this->SetError(self::UPLOAD_ERR_CUSTOM_MOVE,$this->MakeErrorMessage(
                'Upload','UPLOAD_ERR_CUSTOM_MOVE',self::UPLOAD_ERR_CUSTOM_MOVE,'Move file failed.'
            ),'field',$field['fieldName']);
        }
    }

    /**
    * 描述：根据不同的上传代模，返回是否需要停止上传程式的判定。
    */
    private function IsUploadStop(){
        if($this->Type===Uploader::UPLOADTYPE_SINGLE){
            if($this->ErrorCode===NULL||$this->ErrorCode===self::UPLOAD_ERR_OK){
                return FALSE;
            }
            else{
                return TRUE;
            }
        }
        elseif($this->Type===Uploader::UPLOADTYPE_MULTI_ALL){
            if(empty($this->ErrorCode['default'])){
                foreach($this->ErrorCode['field'] as $name=>$code){
                    if($code!==self::UPLOAD_ERR_OK){
                        return TRUE;
                    }
                }
                return FALSE;
            }
            else{
                return TRUE;
            }
        }
        elseif($this->Type===Uploader::UPLOADTYPE_MULTI_PART){
            if(empty($this->ErrorCode['default'])){
                return FALSE;
            }
            else{
                return TRUE;
            }
        }
        elseif($this->Type===Uploader::UPLOADTYPE_MULTIPLEX_ALL){
            if(empty($this->ErrorCode)){
                return FALSE;
            }
            else{
                //@多元异质也要求一点错误没有才能上传，如果发现一个错误则停止。
                foreach($this->ErrorCode as $fieldName=>$code){
                    if($code!==self::UPLOAD_ERR_OK){
                        return TRUE;
                    }
                }
                return FALSE;
            }
        }
        elseif($this->Type===Uploader::UPLOADTYPE_MULTIPLEX_PART){
            //@就算是上传设置错误也不要紧，因为多元异质合格上传每个上传文件有自己的设置，无需理会。
            return FALSE;
        }
    }

    /**
    * 描述：设置错误，并按错误类型写错误日志。
    */
    private function SetError($errorCode,$errorMessge,$errorType=NULL,$errorMeta=NULL){
        if($this->Type===Uploader::UPLOADTYPE_SINGLE){
            $this->ErrorCode=$errorCode;
            $this->ErrorMessage=$errorMessge;
        }
        elseif($this->Type===Uploader::UPLOADTYPE_MULTIPLEX_ALL
             ||$this->Type===Uploader::UPLOADTYPE_MULTIPLEX_PART){
            $this->ErrorCode[$errorMeta]=$errorCode;
            $this->ErrorMessage[$errorMeta]=$errorMessge;
        }
        else{
            if($errorType==='field'){
                $this->ErrorCode['field'][$errorMeta]=$errorCode;
                $this->ErrorMessage['field'][$errorMeta]=$errorMessge;
            }
            else{
                $this->ErrorCode['default']=$errorCode;
                $this->ErrorMessage['default']=$errorMessge;
            }
        }
        #error_log($errorMessge); //感觉全是由客户端可以主动制造的没必要写日志。
    }

    /**
    * 描述：设置错误，并按错误类型写错误日志。
    */
    private function MakeErrorMessage($errorSource,$errorLiterals,$errorCode,$errorMessage){
        return sprintf('TryLibaray::Uploader::%s,literals is `%s`,error code is `%s`,error message is `%s`',
            $errorSource,$errorLiterals,$errorCode,$errorMessage
        );
    }

    /**
    * 描述：获取扩展名。
    * @param  file   require $file 文件对象
    * @return string
    */
    private function GetExtName($filename){
        $tempArray=explode('.', $filename);
        $value=strtolower($tempArray[count($tempArray)-1]);
        return $value;
    }

    /**
    * 描述：自动创建文件上传路径。
    * @param  string $path 必选 路径。
    * @return void
    */
    private function CreatePath($path){
        if(!is_dir($path)){
            $path=explode('/',str_replace('\\','/',$path));
            for($i=0;$i<count($path);$i++){
                $temp=join('/',array_slice($path,0,$i+1));
                if(!empty($temp)&&!is_dir($temp)){
                    mkdir($temp);
                }
            }
        }
    }

    /**
    * 描述：从人理解的角度计算文件大小，并返回相应值。
    * @param  number $bytesize require 字节数。
    * @return string 格式完后的结果。
    */
    public static function SizeFormat($bytesize){
        $i=0;
        #当$bytesize 大于是1024字节时，开始循环，当循环到第4次时跳出；
        while(abs($bytesize)>=1024){
            $bytesize=$bytesize/1024;
            $i++;
            if($i==4){
                break;
            }
        }
        #将Bytes,KB,MB,GB,TB定义成一维数组；
        $units= array("bytes","kb","mb","gb","tb");
        $newsize=round($bytesize,2);
        return("$newsize $units[$i]");
    }
}